Load libraries
library(tidytext)
library(tidyverse)
library(quanteda)
library(lubridate)
library(ggplot2)
library(plotly)
library(forcats)
library(readxl)
library(leaflet)
library(leaflet.minicharts)
library(sp)
library(sf)
library(readr)
library(stringr)
library(rtweet)
library(ggraph)
library(ggrepel)
library(tidygraph)
Load Data
Parlamentarier <- read_csv("Data/Parlamentarier.csv")
EU-Parlament rausfiltern
Parlamentarier <- Parlamentarier %>%
filter(Kategorie!="EU-Parlament")
Read Tabellen mit fehlenden Geschlechtern
alle_geschlechter <- read_excel("Data/Parlamentarier_geschechter.xlsx", sheet = "Geschlechter")
Join fehlende Geschlechterangaben
Parlamentarier <- Parlamentarier %>%
left_join(alle_geschlechter, by = c("Name" = "Name"))
Rename Spalten
Parlamentarier <- Parlamentarier %>%
rename(Geschlecht = Geschlecht.y)
Bundestag Geschlechterverteilung pro Partei
- filtern nach Bundestag
- CDU & CSU zusammenfügen
- nach männlich und weiblich gruppieren, Anzahl berechnen und sortieren
bundestag <- Parlamentarier %>%
select(id, Name, Geschlecht, Partei, Kategorie, SM_Twitter_id, SM_Twitter_user) %>%
filter(Kategorie=="Bundestag")
bundestag$Partei[bundestag$Partei == "CSU"] <-"CDU/CSU"
bundestag$Partei[bundestag$Partei=="CDU"]<-"CDU/CSU"
bundestag_man <- bundestag %>%
group_by(Partei) %>%
filter(Geschlecht == "männlich") %>%
summarise(gesamt_man=n())
bundestag_gesamt <- bundestag %>%
group_by(Partei) %>%
filter(Geschlecht == "weiblich") %>%
summarise(gesamt_frau=n()) %>%
left_join(bundestag_man) %>%
mutate(row_sum=rowSums(.[2:3])) %>%
arrange(desc(row_sum))
Barchart Bundestag
- Stacked-Barchart zur Geschlechterverteilung im Bundestag pro Partei
- visualisierung der Daten in möglichst geschlechterneuralen Farben
plot_ly(data=bundestag_gesamt, x=~reorder(Partei,-row_sum), y=~gesamt_frau, name="weiblich", marker=list(color=toRGB("#FB7F62")),
type="bar", hoverinfo="text", text=~paste("",row_sum),
hovertemplate=paste("Anzahl: %{y:,.0f}",
"<br>Gesamtanzahl: %{text}")) %>%
add_trace(y=~gesamt_man, name="männlich", marker=list(color=toRGB("#775285"))) %>%
layout(barmode="stack", title="Geschlechterverteilung in den Parteien im Bundestag", # titel position und größe ändern
xaxis = list(title = ""), yaxis=list(title="Anzahl Abgeordnete")) %>%
layout(legend=list(x=1, y=0.5))
Landtag Geschlechterverteilung pro Partei
- filtern allen Landtagen
- CDU & CSU sowie FDP & DVP zusammenfügen
- nach männlich und weiblich gruppieren, Anzahl berechnen und sortieren
landtag_partei <- Parlamentarier %>%
filter(Kategorie !="Bundestag") %>%
filter(Kategorie!="EU-Parlament") %>%
filter(Partei !="BIW") %>%
filter(Partei!="SSW") %>%
filter(Partei!="BVB/FW") %>%
filter(Partei!="FW")
landtag_partei$Partei[landtag_partei$Partei == "CSU"] <-"CDU/CSU"
landtag_partei$Partei[landtag_partei$Partei=="CDU"] <- "CDU/CSU"
landtag_partei$Partei[landtag_partei$Partei=="FDP/DVP"] <- "FDP"
landtag_man <- landtag_partei %>%
group_by(Partei) %>%
filter(Geschlecht=="männlich") %>%
summarise(gesamt_man=n())
landtag_gesamt <- landtag_partei %>%
group_by(Partei) %>%
filter(Geschlecht=="weiblich") %>%
summarise(gesamt_frau=n()) %>%
left_join(landtag_man) %>%
mutate(row_sum=rowSums(.[2:3])) %>%
arrange(desc(row_sum))
Joining, by = "Partei"
Barchart Landtag
- Stacked-Barchart zur Geschlechterverteilung in den Landtagen pro Partei
- visualisierung der Daten in möglichst geschlechterneuralen Farben
plot_ly(data=landtag_gesamt, x=~reorder(Partei,-row_sum), y=~gesamt_frau, name="weiblich", marker=list(color=toRGB("#FB7F62")),
type="bar", hoverinfo="text", text=~paste("",row_sum),
hovertemplate=paste("Anzahl: %{y:,.0f}",
"<br>Gesamtanzahl: %{text}")) %>%
add_trace(y=~gesamt_man, name="männlich", marker=list(color=toRGB("#775285"))) %>%
layout(barmode="stack", title="Geschlechterverteilung in den Parteien in den Landtagen", # titel position und größe ändern
xaxis=list(title=""), yaxis=list(title="Anzahl Abgeordnete")) %>%
layout(legend=list(x=1, y=0.5))
Map mit Geschlechterverteilung in den Landtagen
- Alle Landtage herausfiltern
parlamentarier_landtag <- Parlamentarier %>%
filter(Kategorie %in% c("Abgeordnetenhaus von Berlin",
"Bayerischer Landtag",
"Bremische Bürgerschaft",
"Hamburgische Bürgerschaft",
"Hessischer Landtag",
"Landtag Brandenburg",
"Landtag des Saarlandes",
"Landtag Mecklenburg-Vorpommern",
"Landtag Nordrhein-Westfalen",
"Landtag Rheinland-Pfalz",
"Landtag Sachsen-Anhalt",
"Landtag von Baden-Württemberg",
"Niedersächsischer Landtag",
"Sächsischer Landtag",
"Schleswig-Holsteinischer Landtag",
"Thüringer Landtag"))
- Vektoren und Dataframe erstellen mit den Koordinaten an denen die späteren Pie-Charts fixiert werden sollen. (Immer genau im Mittelpunkt des Bundeslandes)
Kategorie <- c("Abgeordnetenhaus von Berlin",
"Bayerischer Landtag",
"Bremische Bürgerschaft",
"Hamburgische Bürgerschaft",
"Hessischer Landtag",
"Landtag Brandenburg",
"Landtag des Saarlandes",
"Landtag Mecklenburg-Vorpommern",
"Landtag Nordrhein-Westfalen",
"Landtag Rheinland-Pfalz",
"Landtag Sachsen-Anhalt",
"Landtag von Baden-Württemberg",
"Niedersächsischer Landtag",
"Sächsischer Landtag",
"Schleswig-Holsteinischer Landtag",
"Thüringer Landtag")
lat <- c(52.520008,
48.917431,
53.074982,
53.553815,
50.652052,
52.408418,
49.396423,
53.612651,
51.433237,
50.118346,
51.950265,
48.661604,
52.636704,
51.104541,
54.219367,
51.010989)
lng <- c(13.404954,
11.407980,
8.807080,
9.991575,
9.162438,
12.562492,
7.022961,
12.429595,
7.661594,
7.308953,
11.692274,
9.350134,
9.845077,
13.201738,
9.696117,
10.845346)
bundeslaender_koordinaten <- data.frame(Kategorie, lat, lng)
- Dataframe nach Anzahl der männlichen und weiblichen Politiker*innen pro Bundesland filtern.
parlamentarier_man <- parlamentarier_landtag %>%
group_by(Kategorie) %>%
filter(Geschlecht == "männlich") %>%
summarise(männlich = n())
parlamentarier_landtag_gesamt <- parlamentarier_landtag %>%
group_by(Kategorie) %>%
filter(Geschlecht == "weiblich") %>%
summarise(weiblich = n()) %>%
left_join(parlamentarier_man)
Joining, by = "Kategorie"
- Koordinaten der späteren Pie-Charts zur Haupttabelle joinen
parlamentarier_koordinaten <- parlamentarier_landtag_gesamt %>%
left_join(bundeslaender_koordinaten, by = c("Kategorie" = "Kategorie"))
Map mit Pie-Charts
- geschlechterneutrale Farben für die Geschlechterverteilung erstellen, sowie die Grenzen der Bundesländer importieren und mit Namen versehen (popup).
colors <- c("#FB7F62", "#775285")
grenzen <- readRDS("Data/gadm36_DEU_1_sp.rds") %>%
st_as_sf()
popup_bundeslaender <- paste0("<strong>Bundesland: </strong>", grenzen$NAME_1)
- Pie-Charts mit Hilfe von addMinicharts zur Karte angefügt.
map <- leaflet() %>%
addProviderTiles(providers$CartoDB.VoyagerLabelsUnder) %>%
setView(lng = 10.451526, lat = 51.165691, zoom = 5.5) %>%
addPolygons(data = grenzen,
fillColor = "grey",
fillOpacity = 0.1,
weight = 3,
color = "grey",
popup = popup_bundeslaender) %>%
addMinicharts(
parlamentarier_koordinaten$lng, parlamentarier_koordinaten$lat,
type = "pie",
chartdata = parlamentarier_koordinaten[, c("weiblich", "männlich")],
colorPalette = colors,
width = 46,
height = 46,
opacity = 0.8,
legendPosition = "bottomright"
)
sf layer has inconsistent datum (+proj=longlat +ellps=WGS84 +towgs84=0,0,0,0,0,0,0 +no_defs).
Need '+proj=longlat +datum=WGS84'
map
Sentimentanalyse
- nach den “großen” Parteien filtern
- alle Politiker*innen entfernen, welche keinen Twitteraccount besitzen
- Usernames in Kleinschreibung formatieren
Parlamentarier_senti <- Parlamentarier %>%
filter(Partei!="BIW") %>%
filter(Partei!="SSW") %>%
filter(Partei!="BVB/FW") %>%
filter(Partei!="FW") %>%
filter(Partei!="fraktionslos") %>%
filter(SM_Twitter_user != "") %>%
select(Name, Partei, SM_Twitter_user, Geschlecht) %>%
mutate(SM_Twitter_user=tolower(SM_Twitter_user))
- CDU & CSU sowie FDP & DVP zusammenfügen
Parlamentarier_senti$Partei[Parlamentarier_senti$Partei == "CSU"] <- "CDU/CSU"
Parlamentarier_senti$Partei[Parlamentarier_senti$Partei == "CDU"] <- "CDU/CSU"
Parlamentarier_senti$Partei[Parlamentarier_senti$Partei == "FDP/DVP"] <- "FDP"
load("Data/sentiWS.RData")
sentiws <- dictionary(list(positive=positive, negative=negative))
- Corpus aus den Texten der gefilterten Tweets bilden
tweet_corpus <- corpus(filtert_tweets, text_field = "text")
- tokenisieren der Texte und bilden einer DFM
- sentiws und “Tweet-Tokens” zusammenführen, sowie nach screen_name gruppieren
token <- tokens(tweet_corpus)
dfm <- dfm(token)
senti <- dfm_lookup(dfm, sentiws)
senti <- dfm_group(senti, groups = screen_name)
- DFM zum Dataframe konvertieren
- doc_id in Kleinschreibung formatieren
- Parlamentarier_senti joinen
- Gruppieren nach Partei
- Sentiment der einzelnen User*innen auf Parteiebene zusammenfassen und Verhältnis positive/negative bilden
senti_frame <- senti %>%
quanteda::convert(to= "data.frame") %>%
as_tibble() %>%
mutate(doc_id=tolower(doc_id))
senti_final_frame <- senti_frame %>%
full_join(Parlamentarier_senti, by=c("doc_id"="SM_Twitter_user")) %>%
group_by(Partei) %>%
summarise(across(c(negative, positive), ~round(sum(., na.rm = TRUE)/sum(negative + positive, na.rm = TRUE ), digits = 2)))
Barchart
- Partei absteigend nach negativem Sentiment sortieren
- Beschriftung der X- und Y Werte ändern
- Barchart bilden und in ggplotly konvertieren
senti_bar <- senti_final_frame %>%
mutate(Partei = fct_reorder(Partei, positive, max)) %>%
pivot_longer(c(positive, negative), values_to = c("Verhältnis"), names_to = c("Äußerung")) %>%
ggplot() +
geom_bar(aes(Partei,
Verhältnis,
fill = Äußerung),
position = "stack",
stat = "identity") +
scale_fill_manual(values = c("#f46666", "#8EC9BB")) +
theme_classic() +
labs(
title = "Äußerungen der Politiker*innen auf Twitter zum Thema 'Gender'",
subtitle = "Einschätzung durch Sentimentanalyse",
x = "Partei",
y = "Verhältnis",
fill = "Äußerung"
)
final_senti_plot <- ggplotly(senti_bar)
final_senti_plot
Netzwerk
Zuweisung von Attributen an Nodes: * Parteizugehörigkeit in Farbe * Klarname der Politikerinnen als Label Anzahl der Tweets in Größe
netz_plot <- netz %>%
filter(component <= 6) %>%
mutate(degree = centrality_degree(mode = "in")) %>%
ggraph(layout = "fr") +
geom_edge_link(alpha = 0.25, arrow = arrow(length = unit("5", "mm"))) +
geom_node_point(aes(size = n, color = Partei)) +
scale_color_manual(values = partei_farben) +
theme_graph(background = "white") + # theme
geom_node_label(aes(filter = n >= 15, label = Name), repel = T, show.legend = F, alpha = 0.5) + #position = "jitter"
labs(title = "Retweet-Netzwerke deutscher Politiker*innen", size = "Anzahl Tweets", subtitle = "zum Thema 'Gender' ab 2016")
netz_plot

NODES DEUTLICHERE ABSTUFUNG, VLT. THEME FUNKTIONIERT NICHT RICHTIG
LS0tDQp0aXRsZTogIlJfUHJvamVrdF9HZW5kZXIiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sgDQotLS0NCiMgTG9hZCBsaWJyYXJpZXMgDQoNCmBgYHtyfQ0KbGlicmFyeSh0aWR5dGV4dCkgDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkocXVhbnRlZGEpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkocGxvdGx5KQ0KbGlicmFyeShmb3JjYXRzKQ0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KGxlYWZsZXQpDQpsaWJyYXJ5KGxlYWZsZXQubWluaWNoYXJ0cykNCmxpYnJhcnkoc3ApDQpsaWJyYXJ5KHNmKQ0KbGlicmFyeShyZWFkcikNCmxpYnJhcnkoc3RyaW5ncikNCmxpYnJhcnkocnR3ZWV0KQ0KbGlicmFyeShnZ3JhcGgpDQpsaWJyYXJ5KGdncmVwZWwpDQpsaWJyYXJ5KHRpZHlncmFwaCkNCmBgYA0KDQojIExvYWQgRGF0YSANCg0KYGBge3J9DQpQYXJsYW1lbnRhcmllciA8LSByZWFkX2NzdigiRGF0YS9QYXJsYW1lbnRhcmllci5jc3YiKQ0KYGBgDQoNCkVVLVBhcmxhbWVudCByYXVzZmlsdGVybg0KYGBge3J9DQpQYXJsYW1lbnRhcmllciA8LSBQYXJsYW1lbnRhcmllciAlPiUgDQogIGZpbHRlcihLYXRlZ29yaWUhPSJFVS1QYXJsYW1lbnQiKQ0KYGBgDQoNClJlYWQgVGFiZWxsZW4gbWl0IGZlaGxlbmRlbiBHZXNjaGxlY2h0ZXJuDQpgYGB7cn0NCmFsbGVfZ2VzY2hsZWNodGVyIDwtIHJlYWRfZXhjZWwoIkRhdGEvUGFybGFtZW50YXJpZXJfZ2VzY2hlY2h0ZXIueGxzeCIsIHNoZWV0ID0gIkdlc2NobGVjaHRlciIpDQpgYGANCg0KSm9pbiBmZWhsZW5kZSBHZXNjaGxlY2h0ZXJhbmdhYmVuIA0KYGBge3J9DQpQYXJsYW1lbnRhcmllciA8LSBQYXJsYW1lbnRhcmllciAlPiUgDQogIGxlZnRfam9pbihhbGxlX2dlc2NobGVjaHRlciwgYnkgPSBjKCJOYW1lIiA9ICJOYW1lIikpDQpgYGANCg0KUmVuYW1lIFNwYWx0ZW4NCmBgYHtyfQ0KUGFybGFtZW50YXJpZXIgPC0gUGFybGFtZW50YXJpZXIgJT4lIA0KICByZW5hbWUoR2VzY2hsZWNodCA9IEdlc2NobGVjaHQueSkNCmBgYA0KDQojIEJ1bmRlc3RhZyBHZXNjaGxlY2h0ZXJ2ZXJ0ZWlsdW5nIHBybyBQYXJ0ZWkNCg0KKiBmaWx0ZXJuIG5hY2ggQnVuZGVzdGFnDQoqIENEVSAmIENTVSB6dXNhbW1lbmbDvGdlbiANCiogbmFjaCBtw6RubmxpY2ggdW5kIHdlaWJsaWNoIGdydXBwaWVyZW4sIEFuemFobCBiZXJlY2huZW4gdW5kIHNvcnRpZXJlbg0KYGBge3J9DQpidW5kZXN0YWcgPC0gUGFybGFtZW50YXJpZXIgJT4lIA0KICBzZWxlY3QoaWQsIE5hbWUsIEdlc2NobGVjaHQsIFBhcnRlaSwgS2F0ZWdvcmllLCBTTV9Ud2l0dGVyX2lkLCBTTV9Ud2l0dGVyX3VzZXIpICU+JSANCiAgZmlsdGVyKEthdGVnb3JpZT09IkJ1bmRlc3RhZyIpDQoNCmJ1bmRlc3RhZyRQYXJ0ZWlbYnVuZGVzdGFnJFBhcnRlaSA9PSAiQ1NVIl0gPC0iQ0RVL0NTVSINCmJ1bmRlc3RhZyRQYXJ0ZWlbYnVuZGVzdGFnJFBhcnRlaT09IkNEVSJdPC0iQ0RVL0NTVSINCg0KYnVuZGVzdGFnX21hbiA8LSBidW5kZXN0YWcgJT4lIA0KICBncm91cF9ieShQYXJ0ZWkpICU+JSANCiAgZmlsdGVyKEdlc2NobGVjaHQgPT0gIm3DpG5ubGljaCIpICU+JSANCiAgc3VtbWFyaXNlKGdlc2FtdF9tYW49bigpKQ0KDQpidW5kZXN0YWdfZ2VzYW10IDwtIGJ1bmRlc3RhZyAlPiUgDQogIGdyb3VwX2J5KFBhcnRlaSkgJT4lIA0KICBmaWx0ZXIoR2VzY2hsZWNodCA9PSAid2VpYmxpY2giKSAlPiUgDQogIHN1bW1hcmlzZShnZXNhbXRfZnJhdT1uKCkpICU+JSANCiAgbGVmdF9qb2luKGJ1bmRlc3RhZ19tYW4pICU+JSANCiAgbXV0YXRlKHJvd19zdW09cm93U3VtcyguWzI6M10pKSAlPiUgDQogIGFycmFuZ2UoZGVzYyhyb3dfc3VtKSkNCmBgYA0KDQojIyMgQmFyY2hhcnQgQnVuZGVzdGFnDQoNCiogU3RhY2tlZC1CYXJjaGFydCB6dXIgR2VzY2hsZWNodGVydmVydGVpbHVuZyBpbSBCdW5kZXN0YWcgcHJvIFBhcnRlaQ0KKiB2aXN1YWxpc2llcnVuZyBkZXIgRGF0ZW4gaW4gbcO2Z2xpY2hzdCBnZXNjaGxlY2h0ZXJuZXVyYWxlbiBGYXJiZW4NCmBgYHtyfQ0KcGxvdF9seShkYXRhPWJ1bmRlc3RhZ19nZXNhbXQsIHg9fnJlb3JkZXIoUGFydGVpLC1yb3dfc3VtKSwgeT1+Z2VzYW10X2ZyYXUsIG5hbWU9IndlaWJsaWNoIiwgbWFya2VyPWxpc3QoY29sb3I9dG9SR0IoIiNGQjdGNjIiKSksDQogICAgICAgIHR5cGU9ImJhciIsIGhvdmVyaW5mbz0idGV4dCIsIHRleHQ9fnBhc3RlKCIiLHJvd19zdW0pLCANCiAgICAgICAgaG92ZXJ0ZW1wbGF0ZT1wYXN0ZSgiQW56YWhsOiAle3k6LC4wZn0iLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiPGJyPkdlc2FtdGFuemFobDogJXt0ZXh0fSIpKSAlPiUgDQogIGFkZF90cmFjZSh5PX5nZXNhbXRfbWFuLCBuYW1lPSJtw6RubmxpY2giLCBtYXJrZXI9bGlzdChjb2xvcj10b1JHQigiIzc3NTI4NSIpKSkgJT4lIA0KICBsYXlvdXQoYmFybW9kZT0ic3RhY2siLCB0aXRsZT0iR2VzY2hsZWNodGVydmVydGVpbHVuZyBpbiBkZW4gUGFydGVpZW4gaW0gQnVuZGVzdGFnIiwgIyB0aXRlbCBwb3NpdGlvbiB1bmQgZ3LDtsOfZSDDpG5kZXJuDQogICAgICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAiIiksIHlheGlzPWxpc3QodGl0bGU9IkFuemFobCBBYmdlb3JkbmV0ZSIpKSAlPiUNCiAgbGF5b3V0KGxlZ2VuZD1saXN0KHg9MSwgeT0wLjUpKQ0KYGBgDQoNCiMgTGFuZHRhZyBHZXNjaGxlY2h0ZXJ2ZXJ0ZWlsdW5nIHBybyBQYXJ0ZWkNCg0KKiBmaWx0ZXJuIGFsbGVuIExhbmR0YWdlbg0KKiBDRFUgJiBDU1Ugc293aWUgRkRQICYgRFZQIHp1c2FtbWVuZsO8Z2VuIA0KKiBuYWNoIG3DpG5ubGljaCB1bmQgd2VpYmxpY2ggZ3J1cHBpZXJlbiwgQW56YWhsIGJlcmVjaG5lbiB1bmQgc29ydGllcmVuDQpgYGB7cn0NCmxhbmR0YWdfcGFydGVpIDwtIFBhcmxhbWVudGFyaWVyICU+JSANCiAgZmlsdGVyKEthdGVnb3JpZSAhPSJCdW5kZXN0YWciKSAlPiUgDQogIGZpbHRlcihLYXRlZ29yaWUhPSJFVS1QYXJsYW1lbnQiKSAlPiUgDQogIGZpbHRlcihQYXJ0ZWkgIT0iQklXIikgJT4lIA0KICBmaWx0ZXIoUGFydGVpIT0iU1NXIikgJT4lIA0KICBmaWx0ZXIoUGFydGVpIT0iQlZCL0ZXIikgJT4lIA0KICBmaWx0ZXIoUGFydGVpIT0iRlciKQ0KYGBgDQoNCmBgYHtyfQ0KbGFuZHRhZ19wYXJ0ZWkkUGFydGVpW2xhbmR0YWdfcGFydGVpJFBhcnRlaSA9PSAiQ1NVIl0gPC0iQ0RVL0NTVSINCmxhbmR0YWdfcGFydGVpJFBhcnRlaVtsYW5kdGFnX3BhcnRlaSRQYXJ0ZWk9PSJDRFUiXSA8LSAiQ0RVL0NTVSINCmxhbmR0YWdfcGFydGVpJFBhcnRlaVtsYW5kdGFnX3BhcnRlaSRQYXJ0ZWk9PSJGRFAvRFZQIl0gPC0gIkZEUCIgDQpgYGANCg0KYGBge3J9DQpsYW5kdGFnX21hbiA8LSBsYW5kdGFnX3BhcnRlaSAlPiUgDQogIGdyb3VwX2J5KFBhcnRlaSkgJT4lIA0KICBmaWx0ZXIoR2VzY2hsZWNodD09Im3DpG5ubGljaCIpICU+JSANCiAgc3VtbWFyaXNlKGdlc2FtdF9tYW49bigpKQ0KDQpsYW5kdGFnX2dlc2FtdCA8LSBsYW5kdGFnX3BhcnRlaSAlPiUgDQogIGdyb3VwX2J5KFBhcnRlaSkgJT4lIA0KICBmaWx0ZXIoR2VzY2hsZWNodD09IndlaWJsaWNoIikgJT4lIA0KICBzdW1tYXJpc2UoZ2VzYW10X2ZyYXU9bigpKSAlPiUgDQogIGxlZnRfam9pbihsYW5kdGFnX21hbikgJT4lIA0KICAgbXV0YXRlKHJvd19zdW09cm93U3VtcyguWzI6M10pKSAlPiUgDQogIGFycmFuZ2UoZGVzYyhyb3dfc3VtKSkNCmBgYA0KDQojIyMgQmFyY2hhcnQgTGFuZHRhZw0KDQoqIFN0YWNrZWQtQmFyY2hhcnQgenVyIEdlc2NobGVjaHRlcnZlcnRlaWx1bmcgaW4gZGVuIExhbmR0YWdlbiBwcm8gUGFydGVpDQoqIHZpc3VhbGlzaWVydW5nIGRlciBEYXRlbiBpbiBtw7ZnbGljaHN0IGdlc2NobGVjaHRlcm5ldXJhbGVuIEZhcmJlbg0KYGBge3J9DQpwbG90X2x5KGRhdGE9bGFuZHRhZ19nZXNhbXQsIHg9fnJlb3JkZXIoUGFydGVpLC1yb3dfc3VtKSwgeT1+Z2VzYW10X2ZyYXUsIG5hbWU9IndlaWJsaWNoIiwgbWFya2VyPWxpc3QoY29sb3I9dG9SR0IoIiNGQjdGNjIiKSksIA0KICAgICAgICB0eXBlPSJiYXIiLCBob3ZlcmluZm89InRleHQiLCB0ZXh0PX5wYXN0ZSgiIixyb3dfc3VtKSwgDQogICAgICAgIGhvdmVydGVtcGxhdGU9cGFzdGUoIkFuemFobDogJXt5OiwuMGZ9IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIjxicj5HZXNhbXRhbnphaGw6ICV7dGV4dH0iKSkgJT4lIA0KICBhZGRfdHJhY2UoeT1+Z2VzYW10X21hbiwgbmFtZT0ibcOkbm5saWNoIiwgbWFya2VyPWxpc3QoY29sb3I9dG9SR0IoIiM3NzUyODUiKSkpICU+JSANCiAgbGF5b3V0KGJhcm1vZGU9InN0YWNrIiwgdGl0bGU9Ikdlc2NobGVjaHRlcnZlcnRlaWx1bmcgaW4gZGVuIFBhcnRlaWVuIGluIGRlbiBMYW5kdGFnZW4iLCAjIHRpdGVsIHBvc2l0aW9uIHVuZCBncsO2w59lIMOkbmRlcm4NCiAgICAgICAgIHhheGlzPWxpc3QodGl0bGU9IiIpLCB5YXhpcz1saXN0KHRpdGxlPSJBbnphaGwgQWJnZW9yZG5ldGUiKSkgJT4lDQogIGxheW91dChsZWdlbmQ9bGlzdCh4PTEsIHk9MC41KSkNCmBgYA0KDQojIE1hcCBtaXQgR2VzY2hsZWNodGVydmVydGVpbHVuZyBpbiBkZW4gTGFuZHRhZ2VuDQoNCiogQWxsZSBMYW5kdGFnZSBoZXJhdXNmaWx0ZXJuDQpgYGB7cn0NCnBhcmxhbWVudGFyaWVyX2xhbmR0YWcgPC0gUGFybGFtZW50YXJpZXIgJT4lIA0KICBmaWx0ZXIoS2F0ZWdvcmllICVpbiUgYygiQWJnZW9yZG5ldGVuaGF1cyB2b24gQmVybGluIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICJCYXllcmlzY2hlciBMYW5kdGFnIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICJCcmVtaXNjaGUgQsO8cmdlcnNjaGFmdCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiSGFtYnVyZ2lzY2hlIELDvHJnZXJzY2hhZnQiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIkhlc3Npc2NoZXIgTGFuZHRhZyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiTGFuZHRhZyBCcmFuZGVuYnVyZyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiTGFuZHRhZyBkZXMgU2FhcmxhbmRlcyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiTGFuZHRhZyBNZWNrbGVuYnVyZy1Wb3Jwb21tZXJuIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICJMYW5kdGFnIE5vcmRyaGVpbi1XZXN0ZmFsZW4iLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIkxhbmR0YWcgUmhlaW5sYW5kLVBmYWx6IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICJMYW5kdGFnIFNhY2hzZW4tQW5oYWx0IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICJMYW5kdGFnIHZvbiBCYWRlbi1Xw7xydHRlbWJlcmciLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk5pZWRlcnPDpGNoc2lzY2hlciBMYW5kdGFnIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICJTw6RjaHNpc2NoZXIgTGFuZHRhZyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiU2NobGVzd2lnLUhvbHN0ZWluaXNjaGVyIExhbmR0YWciLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIlRow7xyaW5nZXIgTGFuZHRhZyIpKQ0KYGBgDQoNCiogVmVrdG9yZW4gdW5kIERhdGFmcmFtZSBlcnN0ZWxsZW4gbWl0IGRlbiBLb29yZGluYXRlbiBhbiBkZW5lbiBkaWUgc3DDpHRlcmVuIFBpZS1DaGFydHMgZml4aWVydCB3ZXJkZW4gc29sbGVuLiAoSW1tZXIgZ2VuYXUgaW0gTWl0dGVscHVua3QgZGVzIEJ1bmRlc2xhbmRlcykNCg0KYGBge3J9DQpLYXRlZ29yaWUgPC0gYygiQWJnZW9yZG5ldGVuaGF1cyB2b24gQmVybGluIiwgDQogICAgICAgICAgICAgICAiQmF5ZXJpc2NoZXIgTGFuZHRhZyIsIA0KICAgICAgICAgICAgICAgIkJyZW1pc2NoZSBCw7xyZ2Vyc2NoYWZ0IiwNCiAgICAgICAgICAgICAgICJIYW1idXJnaXNjaGUgQsO8cmdlcnNjaGFmdCIsIA0KICAgICAgICAgICAgICAgIkhlc3Npc2NoZXIgTGFuZHRhZyIsDQogICAgICAgICAgICAgICAiTGFuZHRhZyBCcmFuZGVuYnVyZyIsIA0KICAgICAgICAgICAgICAgIkxhbmR0YWcgZGVzIFNhYXJsYW5kZXMiLA0KICAgICAgICAgICAgICAgIkxhbmR0YWcgTWVja2xlbmJ1cmctVm9ycG9tbWVybiIsDQogICAgICAgICAgICAgICAiTGFuZHRhZyBOb3JkcmhlaW4tV2VzdGZhbGVuIiwNCiAgICAgICAgICAgICAgICJMYW5kdGFnIFJoZWlubGFuZC1QZmFseiIsDQogICAgICAgICAgICAgICAiTGFuZHRhZyBTYWNoc2VuLUFuaGFsdCIsIA0KICAgICAgICAgICAgICAgIkxhbmR0YWcgdm9uIEJhZGVuLVfDvHJ0dGVtYmVyZyIsIA0KICAgICAgICAgICAgICAgIk5pZWRlcnPDpGNoc2lzY2hlciBMYW5kdGFnIiwgDQogICAgICAgICAgICAgICAiU8OkY2hzaXNjaGVyIExhbmR0YWciLCANCiAgICAgICAgICAgICAgICJTY2hsZXN3aWctSG9sc3RlaW5pc2NoZXIgTGFuZHRhZyIsIA0KICAgICAgICAgICAgICAgIlRow7xyaW5nZXIgTGFuZHRhZyIpDQoNCmxhdCA8LSBjKDUyLjUyMDAwOCwNCiAgICAgICAgIDQ4LjkxNzQzMSwNCiAgICAgICAgIDUzLjA3NDk4MiwNCiAgICAgICAgIDUzLjU1MzgxNSwNCiAgICAgICAgIDUwLjY1MjA1MiwNCiAgICAgICAgIDUyLjQwODQxOCwNCiAgICAgICAgIDQ5LjM5NjQyMywNCiAgICAgICAgIDUzLjYxMjY1MSwNCiAgICAgICAgIDUxLjQzMzIzNywNCiAgICAgICAgIDUwLjExODM0NiwNCiAgICAgICAgIDUxLjk1MDI2NSwNCiAgICAgICAgIDQ4LjY2MTYwNCwNCiAgICAgICAgIDUyLjYzNjcwNCwNCiAgICAgICAgIDUxLjEwNDU0MSwNCiAgICAgICAgIDU0LjIxOTM2NywNCiAgICAgICAgIDUxLjAxMDk4OSkNCg0KbG5nIDwtIGMoMTMuNDA0OTU0LA0KICAgICAgICAgMTEuNDA3OTgwLA0KICAgICAgICAgOC44MDcwODAsDQogICAgICAgICA5Ljk5MTU3NSwNCiAgICAgICAgIDkuMTYyNDM4LA0KICAgICAgICAgMTIuNTYyNDkyLA0KICAgICAgICAgNy4wMjI5NjEsDQogICAgICAgICAxMi40Mjk1OTUsDQogICAgICAgICA3LjY2MTU5NCwNCiAgICAgICAgIDcuMzA4OTUzLA0KICAgICAgICAgMTEuNjkyMjc0LA0KICAgICAgICAgOS4zNTAxMzQsDQogICAgICAgICA5Ljg0NTA3NywNCiAgICAgICAgIDEzLjIwMTczOCwNCiAgICAgICAgIDkuNjk2MTE3LA0KICAgICAgICAgMTAuODQ1MzQ2KQ0KDQpidW5kZXNsYWVuZGVyX2tvb3JkaW5hdGVuIDwtIGRhdGEuZnJhbWUoS2F0ZWdvcmllLCBsYXQsIGxuZykNCmBgYA0KDQoqIERhdGFmcmFtZSBuYWNoIEFuemFobCBkZXIgbcOkbm5saWNoZW4gdW5kIHdlaWJsaWNoZW4gUG9saXRpa2VyKmlubmVuIHBybyBCdW5kZXNsYW5kIGZpbHRlcm4uDQoNCmBgYHtyfQ0KcGFybGFtZW50YXJpZXJfbWFuIDwtIHBhcmxhbWVudGFyaWVyX2xhbmR0YWcgJT4lIA0KICBncm91cF9ieShLYXRlZ29yaWUpICU+JSANCiAgZmlsdGVyKEdlc2NobGVjaHQgPT0gIm3DpG5ubGljaCIpICU+JSANCiAgc3VtbWFyaXNlKG3DpG5ubGljaCA9IG4oKSkNCg0KcGFybGFtZW50YXJpZXJfbGFuZHRhZ19nZXNhbXQgPC0gcGFybGFtZW50YXJpZXJfbGFuZHRhZyAlPiUgDQogIGdyb3VwX2J5KEthdGVnb3JpZSkgJT4lIA0KICBmaWx0ZXIoR2VzY2hsZWNodCA9PSAid2VpYmxpY2giKSAlPiUgDQogIHN1bW1hcmlzZSh3ZWlibGljaCA9IG4oKSkgJT4lIA0KICBsZWZ0X2pvaW4ocGFybGFtZW50YXJpZXJfbWFuKQ0KYGBgDQoNCiogS29vcmRpbmF0ZW4gZGVyIHNww6R0ZXJlbiBQaWUtQ2hhcnRzIHp1ciBIYXVwdHRhYmVsbGUgam9pbmVuDQoNCmBgYHtyfQ0KcGFybGFtZW50YXJpZXJfa29vcmRpbmF0ZW4gPC0gcGFybGFtZW50YXJpZXJfbGFuZHRhZ19nZXNhbXQgJT4lIA0KICBsZWZ0X2pvaW4oYnVuZGVzbGFlbmRlcl9rb29yZGluYXRlbiwgYnkgPSBjKCJLYXRlZ29yaWUiID0gIkthdGVnb3JpZSIpKQ0KYGBgDQoNCiMgTWFwIG1pdCBQaWUtQ2hhcnRzDQoNCiogZ2VzY2hsZWNodGVybmV1dHJhbGUgRmFyYmVuIGbDvHIgZGllIEdlc2NobGVjaHRlcnZlcnRlaWx1bmcgZXJzdGVsbGVuLCBzb3dpZSBkaWUgR3JlbnplbiBkZXIgQnVuZGVzbMOkbmRlciBpbXBvcnRpZXJlbiB1bmQgbWl0IE5hbWVuIHZlcnNlaGVuIChwb3B1cCkuDQpgYGB7cn0NCmNvbG9ycyA8LSBjKCIjRkI3RjYyIiwgIiM3NzUyODUiKQ0KDQpncmVuemVuIDwtIHJlYWRSRFMoIkRhdGEvZ2FkbTM2X0RFVV8xX3NwLnJkcyIpICU+JSANCiAgc3RfYXNfc2YoKQ0KDQpwb3B1cF9idW5kZXNsYWVuZGVyIDwtIHBhc3RlMCgiPHN0cm9uZz5CdW5kZXNsYW5kOiA8L3N0cm9uZz4iLCBncmVuemVuJE5BTUVfMSkNCmBgYA0KDQoqIFBpZS1DaGFydHMgbWl0IEhpbGZlIHZvbiBhZGRNaW5pY2hhcnRzIHp1ciBLYXJ0ZSBhbmdlZsO8Z3QuIA0KDQpgYGB7cn0NCm1hcCA8LSBsZWFmbGV0KCkgJT4lIA0KICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVycyRDYXJ0b0RCLlZveWFnZXJMYWJlbHNVbmRlcikgJT4lIA0KICBzZXRWaWV3KGxuZyA9IDEwLjQ1MTUyNiwgbGF0ID0gNTEuMTY1NjkxLCB6b29tID0gNS41KSAlPiUgDQogIGFkZFBvbHlnb25zKGRhdGEgPSBncmVuemVuLA0KICAgICAgICAgICAgICBmaWxsQ29sb3IgPSAiZ3JleSIsDQogICAgICAgICAgICAgIGZpbGxPcGFjaXR5ID0gMC4xLA0KICAgICAgICAgICAgICB3ZWlnaHQgPSAzLA0KICAgICAgICAgICAgICBjb2xvciA9ICJncmV5IiwNCiAgICAgICAgICAgICAgcG9wdXAgPSBwb3B1cF9idW5kZXNsYWVuZGVyKSAlPiUgDQogIGFkZE1pbmljaGFydHMoDQogICAgcGFybGFtZW50YXJpZXJfa29vcmRpbmF0ZW4kbG5nLCBwYXJsYW1lbnRhcmllcl9rb29yZGluYXRlbiRsYXQsDQogICAgdHlwZSA9ICJwaWUiLA0KICAgIGNoYXJ0ZGF0YSA9IHBhcmxhbWVudGFyaWVyX2tvb3JkaW5hdGVuWywgYygid2VpYmxpY2giLCAibcOkbm5saWNoIildLA0KICAgIGNvbG9yUGFsZXR0ZSA9IGNvbG9ycywNCiAgICB3aWR0aCA9IDQ2LA0KICAgIGhlaWdodCA9IDQ2LA0KICAgIG9wYWNpdHkgPSAwLjgsDQogICAgbGVnZW5kUG9zaXRpb24gPSAiYm90dG9tcmlnaHQiDQogICkNCm1hcA0KYGBgDQoNCiMgVHdlZXRzIGRlciBQb2xpdGlrZXIqaW5uZW4gc2NyYXBlbg0KDQpOaWNodCBhbHMgYXVzZsO8aHJiYXJlbiBDb2RlLCBkYW1pdCBkaWUgRGF0ZW4gbmljaHQgbm9jaG1hbHMgZ2V6b2dlbiB3ZXJkZW4uLi4NCg0KVHdpdHRlcl9hY2NvdW50cyA8LSBQYXJsYW1lbnRhcmllciAlPiUNCiAgZmlsdGVyKEthdGVnb3JpZSE9IkVVLVBhcmxhbWVudCIpICU+JQ0KICBmaWx0ZXIoUGFydGVpIT0iQklXIikgJT4lIA0KICBmaWx0ZXIoUGFydGVpIT0iU1NXIikgJT4lIA0KICBmaWx0ZXIoUGFydGVpIT0iQlZCL0ZXIikgJT4lIA0KICBmaWx0ZXIoUGFydGVpIT0iRlciKSAlPiUgDQogIGZpbHRlcihQYXJ0ZWkhPSJmcmFrdGlvbnNsb3MiKSAlPiUgDQogIGZpbHRlcihTTV9Ud2l0dGVyX3VzZXIgIT0gIiIpDQoNCnRva2VuIDwtIGdldF90b2tlbigpDQp0b2tlbg0KDQphbGxlX3R3ZWV0cyA8LSBsaXN0KCkNCnVzZXJJZExpc3QgPSBsaXN0KFR3aXR0ZXJfYWNjb3VudHMkU01fVHdpdHRlcl91c2VyKQ0KcmwgPC0gcmF0ZV9saW1pdCh0b2tlbiwgInN0YXR1c2VzL3VzZXJfdGltZWxpbmUiKQ0KZm9yKHVzZXIgaW4gdXNlcklkTGlzdFtbMV1dKXsNCiAgYWxsZV90d2VldHNbW3VzZXJdXSA8LSBnZXRfdGltZWxpbmUodXNlciwgbiA9IDIsIGNoZWNrID0gRikNCiAgcHJpbnQoInJhdGUgbGltaXQgcmVtYWluaW5nOiIsIHN0cihybCRyZW1haW5pbmcpKQ0KICBwcmludCgiYXQgdXNlcjoiLCBzdHIodXNlcikpDQogIHJsIDwtIHJsICU+JQ0KICAgIG11dGF0ZShyZW1haW5pbmcgPSByZW1haW5pbmcgLSAxKQ0KICAjIGlmIHJhdGUgbGltaXQgZXhoYXVzdGVkLCB0aGVuIHdhaXQgdG8gcmF0ZSBsaW1pdCByZXNldA0KICBpZiAocmwkcmVtYWluaW5nID09IDVMKSB7DQogICAgcmwgPC0gcmF0ZV9saW1pdCh0b2tlbiwgInN0YXR1c2VzL3VzZXJfdGltZWxpbmUiKQ0KICAgIHByaW50KCJyYXRlIGxpbWl0IGV4Y2VlZGVkLCB3YWl0aW5nIGZvciA5MDBzIGF0IHVzZXIiLCBzdHIodXNlcikpDQogICAgU3lzLnNsZWVwKGFzLm51bWVyaWMocmwkcmVzZXQsICJzZWNzIikpDQogIH0NCn0NCg0KIyMjIE5hY2ggcmVsZXZhbnRlbiBIYXNodGFncyBmaWx0ZXJuIA0KDQoqICJhbGxlX3R3ZWV0cy5yZHMiIGlzdCBkaWUgRGF0ZWkgbWl0IGFsbGVuIGdlem9nZW5lbiBUd2VldHMuDQoqIG5hY2ggcmVsZXZhbnRlbiBUd2VldHMgZmlsdGVybiBtaXQgdm9yaGVyIGJlc3RpbW10ZW4gSGFzaHRhZ3MgKCJUd2l0dGVyLUhhc2h0YWdzLnhsc3giKSwgVHdlZXRzIGluIEtsZWluc2NocmVpYnVuZyBmb3JtYXRpZXJlbiB1bmQgYWxzICJmaW5hbF90d2VldHMucmRzIiBleHBvcnRpZXJlbi4gDQpgYGB7cn0NCmFsbGVfdHdlZXRzIDwtIHJlYWRfcmRzKCJEYXRhL2FsbGVfdHdlZXRzLnJkcyIpDQoNCnN1Y2hiZWdyaWZmZSA8LSByZWFkX2V4Y2VsKCJEYXRhL1R3aXR0ZXItSGFzaHRhZ3MueGxzeCIsIHNoZWV0ID0iVGFiZWxsZTIiKQ0KDQpzdWNoYmVncmlmZmVfdmVjdG9yIDwtIHN1Y2hiZWdyaWZmZSRIYXNodGFncw0KDQphbGxlX3R3ZWV0cyA8LSBiaW5kX3Jvd3MoYWxsZV90d2VldHMpDQoNCmFsbGVfdHdlZXRzIDwtIGFsbGVfdHdlZXRzICU+JSANCiAgbXV0YXRlKHRleHQgPSB0b2xvd2VyKHRleHQpKQ0KDQpmaWx0ZXJ0X3R3ZWV0cyA8LSBhbGxlX3R3ZWV0cyAlPiUgDQogIGZpbHRlcihzdHJfZGV0ZWN0KHRleHQsIHBhc3RlIChzdWNoYmVncmlmZmVfdmVjdG9yLCBjb2xsYXBzZSA9ICJ8IikpKQ0KDQp3cml0ZV9yZHMoZmlsdGVydF90d2VldHMsICJmaW5hbF90d2VldHMucmRzIikNCmBgYA0KDQojIFNlbnRpbWVudGFuYWx5c2UNCg0KKiBuYWNoIGRlbiAiZ3Jvw59lbiIgUGFydGVpZW4gZmlsdGVybg0KKiBhbGxlIFBvbGl0aWtlcippbm5lbiBlbnRmZXJuZW4sIHdlbGNoZSBrZWluZW4gVHdpdHRlcmFjY291bnQgYmVzaXR6ZW4NCiogVXNlcm5hbWVzIGluIEtsZWluc2NocmVpYnVuZyBmb3JtYXRpZXJlbg0KYGBge3J9DQpQYXJsYW1lbnRhcmllcl9zZW50aSA8LSBQYXJsYW1lbnRhcmllciAlPiUgDQogIGZpbHRlcihQYXJ0ZWkhPSJCSVciKSAlPiUgDQogIGZpbHRlcihQYXJ0ZWkhPSJTU1ciKSAlPiUgDQogIGZpbHRlcihQYXJ0ZWkhPSJCVkIvRlciKSAlPiUgDQogIGZpbHRlcihQYXJ0ZWkhPSJGVyIpICU+JSANCiAgZmlsdGVyKFBhcnRlaSE9ImZyYWt0aW9uc2xvcyIpICU+JSANCiAgZmlsdGVyKFNNX1R3aXR0ZXJfdXNlciAhPSAiIikgJT4lIA0KICBzZWxlY3QoTmFtZSwgUGFydGVpLCBTTV9Ud2l0dGVyX3VzZXIsIEdlc2NobGVjaHQpICU+JSANCiAgbXV0YXRlKFNNX1R3aXR0ZXJfdXNlcj10b2xvd2VyKFNNX1R3aXR0ZXJfdXNlcikpDQpgYGANCg0KKiBDRFUgJiBDU1Ugc293aWUgRkRQICYgRFZQIHp1c2FtbWVuZsO8Z2VuIA0KYGBge3J9DQpQYXJsYW1lbnRhcmllcl9zZW50aSRQYXJ0ZWlbUGFybGFtZW50YXJpZXJfc2VudGkkUGFydGVpID09ICJDU1UiXSA8LSAiQ0RVL0NTVSINClBhcmxhbWVudGFyaWVyX3NlbnRpJFBhcnRlaVtQYXJsYW1lbnRhcmllcl9zZW50aSRQYXJ0ZWkgPT0gIkNEVSJdIDwtICJDRFUvQ1NVIg0KUGFybGFtZW50YXJpZXJfc2VudGkkUGFydGVpW1BhcmxhbWVudGFyaWVyX3NlbnRpJFBhcnRlaSA9PSAiRkRQL0RWUCJdIDwtICJGRFAiIA0KYGBgDQoNCiogU2VudGlXUyBpbXBvcnRpZXJlbiwgdW0gcG9zaXRpdmUgdW5kIG5lZ2F0aXZlIFfDtnJ0ZXIgenUga2xhc3NpZml6aWVyZW4NCiogTGlzdGUgenVyIFNlbnRpbWVudGFuYWx5c2UgaXN0IHZvbiBVbml2ZXJzaXTDpHQgTGVpcHppZzogImh0dHBzOi8vd29ydHNjaGF0ei51bmktbGVpcHppZy5kZS9kZS9kb3dubG9hZCINCmBgYHtyfQ0KbG9hZCgiRGF0YS9zZW50aVdTLlJEYXRhIikNCnNlbnRpd3MgPC0gZGljdGlvbmFyeShsaXN0KHBvc2l0aXZlPXBvc2l0aXZlLCBuZWdhdGl2ZT1uZWdhdGl2ZSkpDQpgYGANCg0KKiBDb3JwdXMgYXVzIGRlbiBUZXh0ZW4gZGVyIGdlZmlsdGVydGVuIFR3ZWV0cyBiaWxkZW4NCmBgYHtyfQ0KdHdlZXRfY29ycHVzIDwtIGNvcnB1cyhmaWx0ZXJ0X3R3ZWV0cywgdGV4dF9maWVsZCA9ICJ0ZXh0IikNCmBgYA0KDQoqIHRva2VuaXNpZXJlbiBkZXIgVGV4dGUgdW5kIGJpbGRlbiBlaW5lciBERk0NCiogc2VudGl3cyB1bmQgIlR3ZWV0LVRva2VucyIgenVzYW1tZW5mw7xocmVuLCBzb3dpZSBuYWNoIHNjcmVlbl9uYW1lIGdydXBwaWVyZW4NCg0KYGBge3J9DQp0b2tlbiA8LSB0b2tlbnModHdlZXRfY29ycHVzKQ0KZGZtIDwtIGRmbSh0b2tlbikNCg0Kc2VudGkgPC0gZGZtX2xvb2t1cChkZm0sIHNlbnRpd3MpICANCnNlbnRpIDwtIGRmbV9ncm91cChzZW50aSwgZ3JvdXBzID0gc2NyZWVuX25hbWUpDQpgYGANCg0KKiBERk0genVtIERhdGFmcmFtZSBrb252ZXJ0aWVyZW4NCiogZG9jX2lkIGluIEtsZWluc2NocmVpYnVuZyBmb3JtYXRpZXJlbg0KKiBQYXJsYW1lbnRhcmllcl9zZW50aSBqb2luZW4NCiogR3J1cHBpZXJlbiBuYWNoIFBhcnRlaQ0KKiBTZW50aW1lbnQgZGVyIGVpbnplbG5lbiBVc2VyKmlubmVuIGF1ZiBQYXJ0ZWllYmVuZSB6dXNhbW1lbmZhc3NlbiB1bmQgVmVyaMOkbHRuaXMgcG9zaXRpdmUvbmVnYXRpdmUgYmlsZGVuDQpgYGB7cn0NCnNlbnRpX2ZyYW1lIDwtIHNlbnRpICU+JSANCiAgcXVhbnRlZGE6OmNvbnZlcnQodG89ICJkYXRhLmZyYW1lIikgJT4lIA0KICBhc190aWJibGUoKSAlPiUgDQogIG11dGF0ZShkb2NfaWQ9dG9sb3dlcihkb2NfaWQpKQ0KDQpzZW50aV9maW5hbF9mcmFtZSA8LSBzZW50aV9mcmFtZSAlPiUgDQogIGZ1bGxfam9pbihQYXJsYW1lbnRhcmllcl9zZW50aSwgYnk9YygiZG9jX2lkIj0iU01fVHdpdHRlcl91c2VyIikpICU+JSANCiAgZ3JvdXBfYnkoUGFydGVpKSAlPiUgDQogIHN1bW1hcmlzZShhY3Jvc3MoYyhuZWdhdGl2ZSwgcG9zaXRpdmUpLCB+cm91bmQoc3VtKC4sIG5hLnJtID0gVFJVRSkvc3VtKG5lZ2F0aXZlICsgcG9zaXRpdmUsIG5hLnJtID0gVFJVRSApLCBkaWdpdHMgPSAyKSkpDQpgYGANCg0KIyMjIEJhcmNoYXJ0DQoNCiogUGFydGVpIGFic3RlaWdlbmQgbmFjaCBuZWdhdGl2ZW0gU2VudGltZW50IHNvcnRpZXJlbg0KKiBCZXNjaHJpZnR1bmcgZGVyIFgtIHVuZCBZIFdlcnRlIMOkbmRlcm4NCiogQmFyY2hhcnQgYmlsZGVuIHVuZCBpbiBnZ3Bsb3RseSBrb252ZXJ0aWVyZW4NCmBgYHtyfQ0Kc2VudGlfYmFyIDwtIHNlbnRpX2ZpbmFsX2ZyYW1lICU+JSANCiAgbXV0YXRlKFBhcnRlaSA9IGZjdF9yZW9yZGVyKFBhcnRlaSwgcG9zaXRpdmUsIG1heCkpICU+JSANCiAgcGl2b3RfbG9uZ2VyKGMocG9zaXRpdmUsIG5lZ2F0aXZlKSwgdmFsdWVzX3RvID0gYygiVmVyaMOkbHRuaXMiKSwgbmFtZXNfdG8gPSBjKCLDhHXDn2VydW5nIikpICU+JSANCiAgZ2dwbG90KCkgKyANCiAgZ2VvbV9iYXIoYWVzKFBhcnRlaSwNCiAgICAgICAgICAgICAgIFZlcmjDpGx0bmlzLCAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgZmlsbCA9IMOEdcOfZXJ1bmcpLA0KICAgICAgICAgICBwb3NpdGlvbiA9ICJzdGFjayIsDQogICAgICAgICAgIHN0YXQgPSAiaWRlbnRpdHkiKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNmNDY2NjYiLCAiIzhFQzlCQiIpKSArIA0KICB0aGVtZV9jbGFzc2ljKCkgKyANCiAgbGFicygNCiAgICB0aXRsZSA9ICLDhHXDn2VydW5nZW4gZGVyIFBvbGl0aWtlcippbm5lbiBhdWYgVHdpdHRlciB6dW0gVGhlbWEgJ0dlbmRlciciLA0KICAgIHN1YnRpdGxlID0gIkVpbnNjaMOkdHp1bmcgZHVyY2ggU2VudGltZW50YW5hbHlzZSIsDQogICAgeCA9ICJQYXJ0ZWkiLA0KICAgIHkgPSAiVmVyaMOkbHRuaXMiLA0KICAgIGZpbGwgPSAiw4R1w59lcnVuZyINCiAgKQ0KDQpmaW5hbF9zZW50aV9wbG90IDwtIGdncGxvdGx5KHNlbnRpX2JhcikNCmZpbmFsX3NlbnRpX3Bsb3QNCmBgYA0KDQojIFR3aXR0ZXIgTmV0endlcmsgDQoNCiogZmlsdGVydF90d2VldHMgInZlcmtsZWluZXJuIiB1bmQgaW4gdHdlZXRzX25ldHdvcmsgc3BlaWNoZXJuDQoqIHNjcmVlbl9uYW1lIGluIEtsZWluc2NocmVpYnVuZyBmb3JtYXRpZXJlbg0KYGBge3J9DQp0d2VldHNfbmV0d29yayA8LSBmaWx0ZXJ0X3R3ZWV0cyAlPiUgDQogIHNlbGVjdChzY3JlZW5fbmFtZSwNCiAgICAgICAgIHJldHdlZXRfc2NyZWVuX25hbWUsDQogICAgICAgICBjcmVhdGVkX2F0KSAlPiUgDQogIG11dGF0ZShzY3JlZW5fbmFtZSA9IHRvbG93ZXIoc2NyZWVuX25hbWUpKQ0KYGBgDQoNCiogUGFybGFtZW50YXJpZXIgRGF0YWZyYW1lIG1pdCB0d2VldHNfbmV0d29yayBqb2luZW4sIHVtIEtsYXJhbWVuIHVuZCBQYXJ0ZWl6dWdlaMO2cmlna2VpdCBkZXIgUG9saXRpa2VyKmlubm5lbiB6dSBiZWtvbW1lbg0KYGBge3J9DQpwYXJsYW1lbnRhcmllcl9uZXR3b3JrIDwtIFBhcmxhbWVudGFyaWVyICU+JSANCiAgc2VsZWN0KE5hbWUsDQogICAgICAgICBQYXJ0ZWksDQogICAgICAgICBTTV9Ud2l0dGVyX3VzZXIpICU+JSANCiAgZHJvcF9uYShTTV9Ud2l0dGVyX3VzZXIpICU+JSANCiAgbXV0YXRlKFNNX1R3aXR0ZXJfdXNlciA9IHRvbG93ZXIoU01fVHdpdHRlcl91c2VyKSkgJT4lIA0KICByZW5hbWUoInNjcmVlbl9uYW1lIiA9ICJTTV9Ud2l0dGVyX3VzZXIiKQ0KDQpuZXR3b3JrX2RhdGEgPC0gcGFybGFtZW50YXJpZXJfbmV0d29yayAlPiUgDQogIGxlZnRfam9pbih0d2VldHNfbmV0d29yaywgYnkgPSAic2NyZWVuX25hbWUiKQ0KYGBgDQoNCiogSMOkdWZpZ2tlaXQgZGVyIFR3ZWV0cyB6dW0gVGhlbWEgYmVyZWNobmVuIA0KKiBIw6R1Zmlna2VpdCB6dSBuZXR3b3JrX2RhdGEgam9pbmVuDQpgYGB7cn0NCmhhdWVmaWdrZWl0X3R3ZWV0cyA8LSBuZXR3b3JrX2RhdGEgJT4lIA0KICBjb3VudChzY3JlZW5fbmFtZSkNCg0KbmV0d29ya19kYXRhIDwtIG5ldHdvcmtfZGF0YSAlPiUgDQogIGxlZnRfam9pbihoYXVlZmlna2VpdF90d2VldHMsIGJ5ID0gInNjcmVlbl9uYW1lIikNCmBgYA0KDQoqIFZla3RvciBkZXIgc2NyZWVuX25hbWVzIGFsbGVyIFBvbGl0aWtlcippbm5lbiBlcnN0ZWxsZW4NCiogcmV0d2VldF9zY3JlZW5fbmFtZSBhdWYgZGllc2Ugc2NyZWVuX25hbWVzIGZpbHRlcm4sIHVtICJGcmVtZHVzZXIqaW5uZW4iIGF1c3p1c2NobGllw59lbiANCmBgYHtyfQ0Kc2NyZWVuX3N1Y2hlIDwtIHBhcmxhbWVudGFyaWVyX25ldHdvcmskc2NyZWVuX25hbWUNCg0KZmlsdGVyZWRfcmV0d2VldGVycyA8LSBuZXR3b3JrX2RhdGEgJT4lIA0KICBmaWx0ZXIoc3RyX2RldGVjdChyZXR3ZWV0X3NjcmVlbl9uYW1lLCBwYXN0ZSAoc2NyZWVuX3N1Y2hlLCBjb2xsYXBzZSA9ICJ8IikpKQ0KYGBgDQoNCiogTmV0eiBtaXQgcmVsZXZhbnRlbiBXZXJ0ZW4gZGVmaW5pZXJlbiBtaXQ6IA0KKiBFZGdlcyA9IHZvbiBzY3JlZW5fbmFtZSB6dSByZXR3ZWV0X3NjcmVlbl9uYW1lDQoqIE5vZGVzID0gUG9saXRpa2VyKmlubmVuIChzY3JlZW5fbmFtZSB1bmQgcmV0d2VldF9zY3JlZW5fbmFtZSkgDQoqIEpvaW5lIGF1ZnMgTmV0eiBQYXJ0ZWl6dWdlaMO2cmlna2VpdCwgS2xhcm5hbWVuIHVuZCBIw6R1Zmlna2VpdCBkZXIgVHdlZXRzIHp1bSBUaGVtYSAobikNCmBgYHtyfQ0KbmV0eiA8LSBmaWx0ZXJlZF9yZXR3ZWV0ZXJzICU+JSANCiAgZmlsdGVyKCFpcy5uYShyZXR3ZWV0X3NjcmVlbl9uYW1lKSkgJT4lIA0KICBzZWxlY3QoZnJvbSA9IHNjcmVlbl9uYW1lLCB0byA9IHJldHdlZXRfc2NyZWVuX25hbWUpICU+JSANCiAgYXNfdGJsX2dyYXBoDQoNCm5ldHogPC0gbmV0eiAlPiUgDQogIG11dGF0ZSgNCiAgICBkZWdyZWUgPSBjZW50cmFsaXR5X2RlZ3JlZShtb2RlID0gImluIiksIA0KICAgIGNvbXBvbmVudCA9IGdyb3VwX2NvbXBvbmVudHMoKQ0KICApICU+JSANCiAgbGVmdF9qb2luKG5ldHdvcmtfZGF0YSAlPiUgDQogICAgICAgICAgICAgIHNlbGVjdChOYW1lLCBzY3JlZW5fbmFtZSwgUGFydGVpLCBuKSAlPiUgZGlzdGluY3Qoc2NyZWVuX25hbWUsIC5rZWVwX2FsbCA9IFQpLA0KICAgICAgICAgICAgYnkgPSBjKCAibmFtZSIgPSJzY3JlZW5fbmFtZSIpKSANCmBgYA0KDQoqIEZhcmJlbiBmw7xyIFBhcnRlaWVuIGRlZmluaWVyZW4NCmBgYHtyfQ0KcGFydGVpX2ZhcmJlbiA8LSBsaXN0KA0KICAiQ0RVL0NTVSIgPSAiYmxhY2siLA0KICAiU1BEIiA9ICJyZWQiLA0KICAiQ1NVIiA9ICJibGFjayIsDQogICJGRFAiID0gIiNlMmIwMDciLA0KICAiR1LDnE5FIiA9ICIjMDdDMjNGIiwNCiAgIkxJTktFIiA9ICIjZGU0YzhhIiwgDQogICJBZkQiID0gImJsdWUiDQopDQpgYGANCg0KIyBOZXR6d2Vyaw0KDQpadXdlaXN1bmcgdm9uIEF0dHJpYnV0ZW4gYW4gTm9kZXM6DQoqIFBhcnRlaXp1Z2Vow7ZyaWdrZWl0IGluIEZhcmJlDQoqIEtsYXJuYW1lIGRlciBQb2xpdGlrZXIqaW5uZW4gYWxzIExhYmVsIA0KKiBBbnphaGwgZGVyIFR3ZWV0cyBpbiBHcsO2w59lDQpgYGB7cn0NCm5ldHpfcGxvdCA8LSBuZXR6ICU+JSANCiAgZmlsdGVyKGNvbXBvbmVudCA8PSA2KSAlPiUgDQogIG11dGF0ZShkZWdyZWUgPSBjZW50cmFsaXR5X2RlZ3JlZShtb2RlID0gImluIikpICU+JSANCiAgZ2dyYXBoKGxheW91dCA9ICJmciIpICsNCiAgZ2VvbV9lZGdlX2xpbmsoYWxwaGEgPSAwLjI1LCBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoIjUiLCAibW0iKSkpICsNCiAgZ2VvbV9ub2RlX3BvaW50KGFlcyhzaXplID0gbiwgY29sb3IgPSBQYXJ0ZWkpKSArIA0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFydGVpX2ZhcmJlbikgKw0KICB0aGVtZV9ncmFwaChiYWNrZ3JvdW5kID0gIndoaXRlIikgKyAjIHRoZW1lDQogIGdlb21fbm9kZV9sYWJlbChhZXMoZmlsdGVyID0gbiA+PSAxNSwgbGFiZWwgPSBOYW1lKSwgcmVwZWwgPSBULCBzaG93LmxlZ2VuZCA9IEYsIGFscGhhID0gMC41KSArICNwb3NpdGlvbiA9ICJqaXR0ZXIiDQogIGxhYnModGl0bGUgPSAiUmV0d2VldC1OZXR6d2Vya2UgZGV1dHNjaGVyIFBvbGl0aWtlcippbm5lbiIsIHNpemUgPSAiQW56YWhsIFR3ZWV0cyIsIHN1YnRpdGxlID0gInp1bSBUaGVtYSAnR2VuZGVyJyBhYiAyMDE2IikNCmBgYA0KYGBge3J9DQpuZXR6X3Bsb3QgDQpgYGANCg0KTk9ERVMgREVVVExJQ0hFUkUgQUJTVFVGVU5HLCBWTFQuIFRIRU1FIEZVTktUSU9OSUVSVCBOSUNIVCBSSUNIVElHDQo=